#ifndef __YSIP2__H__
#define __YSIP2__H__


#include<string>
#include<fstream>
#include<iostream>
#include<sstream>
#include<vector>
#include<algorithm>

#define YSIP_MAX_LEVEL 10 
#define YSIP_MIN_LEVEL 0
#define YSIP_LEVEL_COUNTRY 0 
#define YSIP_LEVEL_PROVINCE 1
#define YSIP_LEVEL_AREA 2
#define YSIP_LEVEL_CITY 3

#define MAX_REGION_NAME_LENGTH 48

#ifndef YSIP_ROOT
#define YSIP_ROOT ""
#endif

using namespace std;

typedef struct _YSIP2_IP_INFO YSIP2_IP_INFO;
typedef struct _YSIP2_REGION_INFO YSIP2_REGION_INFO;
#ifdef YSIP2_IP_DATA_ALL
typedef struct _YSIP2_REGION_INFO_EX YSIP2_REGION_INFO_EX;
#endif

typedef struct _YSIP2_IP_INFO{
	unsigned int minip;
	unsigned int maxip;
	int64_t region_id;
#ifdef YSIP2_IP_DATA_ALL
	int position;
#endif

#ifdef YSIP2_IP_DATA_ALL
	_YSIP2_IP_INFO() : minip(0),maxip(0),region_id(0), position(0){}
#else
	_YSIP2_IP_INFO() : minip(0),maxip(0),region_id(0){}
#endif

	friend inline ostream & operator << (ostream &os, YSIP2_IP_INFO & ipInfo) {
		os << "minip: " << ipInfo.minip << endl;
		os << "maxip: " << ipInfo.maxip << endl;
		os << "region_id: " << ipInfo.region_id << endl;
#ifdef YSIP2_IP_DATA_ALL
		os << "position: " << ipInfo.position << endl;
#endif
		return os;
	}
	YSIP2_IP_INFO & operator = (YSIP2_IP_INFO other) {
		if( minip != other.minip) {
			minip = other.minip;
			maxip = other.maxip;
			region_id = other.region_id;
#ifdef YSIP2_IP_DATA_ALL
			position = other.position;
#endif
		}	
		return *this;
	}
	YSIP2_IP_INFO & operator = (unsigned int oid) {
		minip = maxip = oid;
		region_id = 0;
#ifdef YSIP2_IP_DATA_ALL
		position = 0;
#endif
		return *this;
	}
	YSIP2_IP_INFO & operator = (YSIP2_IP_INFO * other) {
		if(minip != other->minip) {
			minip = other->minip;
			maxip = other->maxip;
			region_id = other->region_id;
#ifdef YSIP2_IP_DATA_ALL
			region_id = other->position;
#endif
		}
		return *this;
	}
	YSIP2_IP_INFO & operator << (const string buffer) {
		stringstream ss(buffer);
		ss >> minip >> maxip >> region_id;
#ifdef YSIP2_IP_DATA_ALL
		ss >> position;
#endif
		return * this;
	}
	YSIP2_IP_INFO & operator = (const string buffer) {
		stringstream ss(buffer);
		ss >> minip >> maxip >> region_id;
#ifdef YSIP2_IP_DATA_ALL
		ss >> position;
#endif
		return * this;
	}
	bool operator == (unsigned int ip){
		return minip <= ip && maxip >= ip;
	};
	bool operator > (unsigned int ip) {
		return minip > ip;
	}
	bool operator < (unsigned int ip) {
		return maxip < ip;
	}
	size_t size() {
		return sizeof(YSIP2_IP_INFO);
	}
} YSIP2_IP_INFO;

typedef struct _YSIP2_REGION_INFO{
	int64_t id;
	int64_t parent_id;
	int parent_pos;
	int level;
	char name[MAX_REGION_NAME_LENGTH]; // through compute got 45  48 = 12 * 4;

	_YSIP2_REGION_INFO():id(0),parent_id(0),parent_pos(0), level(0){
		name[0] = '\0';
	}
	YSIP2_REGION_INFO & operator = (YSIP2_REGION_INFO other) {
		if(id != other.id) {
			id = other.id;
			parent_id = other.parent_id;
			parent_pos = other.parent_pos;
			strncpy(name, other.name, MAX_REGION_NAME_LENGTH);
			level = other.level;
		}
		return * this;
	}
	YSIP2_REGION_INFO & operator = (YSIP2_REGION_INFO * other) {
		if(id != other->id) {
			id = other->id;
			parent_pos = other->parent_pos;
			parent_id = other->parent_id;
			strncpy(name, other->name, MAX_REGION_NAME_LENGTH);
			level = other->level;
		}
		return * this;
	}
	YSIP2_REGION_INFO & operator = (int64_t oid) {
		if(id != oid) {
			id = oid;
			parent_id = 0;
			parent_pos = 0;
			name[0] = '\0';
			level = 0;
		}
		return * this;
	}
	friend inline ostream & operator << (ostream &os, YSIP2_REGION_INFO & regionInfo) {
		os << "id: " << regionInfo.id << endl;
		os << "parent_id: " << regionInfo.parent_id << endl;
		os << "name: " << regionInfo.name << endl;
		os << "parent_pos: " << regionInfo.parent_pos << endl;
		os << "level: " << regionInfo.level << endl;
		return os;
	}

	YSIP2_REGION_INFO & operator << (const string buffer) {
		stringstream ss(buffer);
		ss >> id >> name >> parent_id >> parent_pos >> level;
		return * this;
	}

	YSIP2_REGION_INFO & operator = (const string buffer) {
		stringstream ss(buffer);
		ss >> id >> name >> parent_id >> parent_pos >> level;
		return * this;
	}
	bool operator == (int64_t oid) {
		return id == oid;
	}
	bool operator > (int64_t oid) {
		return id > oid;
	}
	bool operator < (int64_t oid) {
		return id < oid;
	}
	size_t size() {
		return sizeof(YSIP2_REGION_INFO);
	}
} YSIP2_REGION_INFO;

#ifdef YSIP2_IP_DATA_ALL
typedef struct _YSIP2_REGION_INFO_EX : public YSIP2_REGION_INFO {
	string detail;
	_YSIP2_REGION_INFO_EX():detail("") {};

	YSIP2_REGION_INFO_EX & operator = (YSIP2_REGION_INFO other) {
		if(id != other.id) {
			id = other.id;
			parent_id = other.id;
			parent_pos = other.parent_pos;
			level = other.level;
			strncpy(name, other.name, MAX_REGION_NAME_LENGTH);
			detail = "";
		}
		return * this;
	};

	YSIP2_REGION_INFO_EX & operator = (YSIP2_REGION_INFO_EX other) {
		if(id != other.id) {
			id = other.id;
			parent_id = other.id;
			parent_pos = other.parent_pos;
			level = other.level;
			strncpy(name, other.name, MAX_REGION_NAME_LENGTH);
			detail = other.detail;
		}
		return * this;
	};

	friend inline ostream & operator << (ostream &os, YSIP2_REGION_INFO_EX & regionInfo) {
		os << "id: " << regionInfo.id << endl;
		os << "parent_id: " << regionInfo.parent_id << endl;
		os << "name: " << regionInfo.name << endl;
		os << "parent_pos: " << regionInfo.parent_pos << endl;
		os << "level: " << regionInfo.level << endl;
		os << "detail: " << regionInfo.detail << endl;
		return os;	
	}
	size_t size() {
		return sizeof(YSIP2_REGION_INFO_EX);
	}
} YSIP2_REGION_INFO_EX;
#endif


bool ysipInit(const string root = "");
void ysipDestory();


bool ysipGetIpInfo(const string ip, YSIP2_REGION_INFO & regionInfo);
#ifdef YSIP2_IP_DATA_ALL
bool ysipGetIpInfo(const string ip, YSIP2_REGION_INFO_EX & regionInfo);
#endif
bool ysipGetRegionInfo(const int64_t id, YSIP2_REGION_INFO & regionInfo);
bool ysipGetRegionChilds(const int64_t id, vector<YSIP2_REGION_INFO> & childs, bool includeSelf = true);
bool ysipGetRegionParent(const int64_t id, YSIP2_REGION_INFO &regionInfo);
bool ysipGetRegionParents(const int64_t id, vector<YSIP2_REGION_INFO> & parents, bool includeSelf = true, int level = YSIP_MIN_LEVEL);
int ysipGetStat(int type = 0);

#ifdef DEBUG
#define DEBUG1(x) cerr << (x) << endl;
#define DEBUG2(x,y) cerr << (x) << (y) << endl;
#define DEBUG3(x,y,z) cerr << (x) << (y) << (z) << endl;
#define DEBUG4(m,n,x,y) cout << (m) << (n) << (x) << (y) << endl;
#else
#define DEBUG1
#define DEBUG2
#define DEBUG3
#define DEBUG4
#endif

#endif
